package com.gitee.feizns.quickstart.ding.talk.spring.boot.autoconfigure.db.mybatis.flex;

import com.dingtalk.api.response.OapiV2DepartmentGetResponse;
import com.dingtalk.api.response.OapiV2UserGetResponse;
import com.gitee.feizns.quickstart.ding.talk.spring.boot.autoconfigure.db.mybatis.flex.mapper.DdDeptMapper;
import com.gitee.feizns.quickstart.ding.talk.spring.boot.autoconfigure.db.mybatis.flex.mapper.DdUserMapper;
import com.gitee.feizns.quickstart.ding.talk.spring.boot.autoconfigure.db.mybatis.flex.pojo.DdDept;
import com.gitee.feizns.quickstart.ding.talk.spring.boot.autoconfigure.db.mybatis.flex.pojo.DdUser;
import com.gitee.feizns.quickstart.ding.talk.spring.boot.autoconfigure.domain.vo.DdDeptUserIdListVo;
import com.gitee.feizns.dynamic.bean.Beans;
import com.gitee.feizns.quickstart.ding.talk.api.top.api.ContactsApi;
import com.gitee.feizns.quickstart.ding.talk.api.v10.oauth2.AccessToken;
import com.gitee.feizns.quickstart.ding.talk.event.contacts.ContactsEventListener;
import lombok.RequiredArgsConstructor;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 联系人同步器
 * @author feizns
 * @since 2025/3/28
 */
@RequiredArgsConstructor
public class ContactsSynchronizer implements ContactsEventListener {

    /**
     * 联系人 API
     */
    private final ContactsApi contactsApi;

    @Override
    public AccessToken accessToken() {
        return contactsApi.getAccessToken();
    }

    @Override
    public void onInsertUser(String userid, OapiV2UserGetResponse.UserGetResponse user) {
        syncUserToDb(user);
    }

    @Override
    public void onInsertDept(OapiV2DepartmentGetResponse.DeptGetResponse dept) {
        syncDeptToDb(dept);
    }

    @Override
    public void onUpdateUser(OapiV2UserGetResponse.UserGetResponse user) {
        syncUserToDb(user);
    }

    @Override
    public void onUpdateDept(OapiV2DepartmentGetResponse.DeptGetResponse dept) {
        syncDeptToDb(dept);
    }

    @Override
    public void onDeleteUser(String userid) {
        DdUserMapper.removeByUserid(userid);
    }

    @Override
    public void onDeleteDept(Long deptId) {
        DdDeptMapper.removeByDeptId(deptId);
    }

    /**
     * 将钉钉用户同步到数据库
     * @param user 用户
     * @return {@link DdUser }
     */
    public DdUser syncUserToDb(OapiV2UserGetResponse.UserGetResponse user) {
        DdUser dbDdUser = DdUserMapper.findByUseridAsOpt(user.getUserid()).orElse(new DdUser());
        Beans.copyProperties(dbDdUser, user);
        dbDdUser.saveOrUpdate();
        return dbDdUser;
    }

    /**
     * 将指定部门下的用户同步到数据库
     * @param ddDeptList 部门列表
     * @return {@link List }<{@link DdUser}>
     */
    public List<DdUser> syncUserToDb(List<DdDept> ddDeptList) {
        List<DdUser> result = new ArrayList<>();
        for (DdDept ddDept : ddDeptList) {
            List<String> useridList = contactsApi.getUseridListByDeptId(ddDept.getDeptId());
            for (String userid : useridList)
                syncUserToDb(contactsApi.getUser(userid));
        }
        return result;
    }

    /**
     * 同步钉话部门到数据库
     * @return {@link DdDept }
     */
    public DdDept syncDeptToDb(OapiV2DepartmentGetResponse.DeptGetResponse dept) {
        //查询数据库中是否已有该部门
        DdDept dbDdDept = DdDeptMapper.findByDdDeptIdAsOpt(dept.getDeptId()).orElse(new DdDept());
        Beans.copyProperties(dbDdDept, dept);
        if ( dbDdDept.getId() != null ) {
            dbDdDept.updateById();
        } else {
            dbDdDept.setId(dept.getDeptId());
            dbDdDept.save();
        }
        return dbDdDept;
    }

    /**
     * 获取所有部门
     * @return {@link List }<{@link Long }>
     */
    public List<DdDept> syncDeptToDb() {
        List<DdDept> result = new ArrayList<>();
        contactsApi.eachDept(dept -> result.add(syncDeptToDb(dept)));
        return result;
    }

    /**
     * 部门及其用户编号列表
     * @return {@link List }<{@link String }>
     */
    public List<DdDeptUserIdListVo> deptUserIdList() {
        List<DdDeptUserIdListVo> result = new ArrayList<>();
        contactsApi.eachDept(dept -> result.add(new DdDeptUserIdListVo(dept.getDeptId(), contactsApi.getUseridListByDeptId(dept.getDeptId()))));
        return result;
    }

    /**
     * 删除已删除的用户和部门
     */
    public void deleteDeletedUsersAndDepartments() {
        //删除已删除的部门
        List<DdDeptUserIdListVo> vos = deptUserIdList();
        //钉钉存在的部门编号
        Set<Long> dingTalkDeptIdList = vos.stream().map(DdDeptUserIdListVo::getDeptId).collect(Collectors.toSet());
        //数据库存在的部门编号
        Set<Long> databaseDeptIdList = DdDeptMapper.findDeptIdList();
        for (Long deptId : databaseDeptIdList) {
            if ( !dingTalkDeptIdList.contains(deptId) )
                DdDeptMapper.removeByDeptId(deptId);
        }
        //删除已删除的用户
        //钉钉存在的用户编号
        Set<String> dingTalkUseridList = vos.stream().map(DdDeptUserIdListVo::getUserIdList).flatMap(List::stream).collect(Collectors.toSet());
        //数据库的用户编号
        List<String> databaseUseridList = DdUserMapper.findUseridList();
        for (String userid : databaseUseridList) {
            if ( !dingTalkUseridList.contains(userid) )
                DdUserMapper.removeByUserid(userid);
        }
    }

    /**
     * 同步联系人（部门、用户）
     */
    public void syncUserAndDept() {
        //同步部门和用户
        syncUserToDb(syncDeptToDb());
        //删除已注销用户
        deleteDeletedUsersAndDepartments();
    }

}
